package com.sia.springcloud.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sia.springcloud.mapper.DeviceMapper;
import com.sia.springcloud.mapper.PointMapper;
import com.sia.springcloud.model.Device;
import com.sia.springcloud.model.Point;
import com.sia.springcloud.protocol.model.BoschDevice;
import com.sia.springcloud.service.IDeviceService;
import com.sia.springcloud.result.GridDataResult;
import com.sia.springcloud.result.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: Sirius
 * @Date: 2021/12/21 1:20
 * @Description: 通信协议设备服务层接口实现类
 * 主要提供的方法：添加设备、分页查询设备、根据微服务名称查询正在数采的设备、批量删除设备、修改指定设备
 */
@Slf4j
@Service("DeviceService")
public class DeviceService extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {

    @Resource
    private DeviceMapper deviceMapper;

    @Resource
    private PointMapper pointMapper;

    /**
     * 添加设备
     *
     * @param device
     * @return
     */
    public String insertDevice(Device device) {
        log.info("插入点位：{}",device.toString());


        //查询数据库中是否有不同设备id，相同设备名的设备，如果有则不能插入
        QueryWrapper<Device> deviceQueryWrapper = new QueryWrapper<>();

        deviceQueryWrapper.eq("protocol_name", device.getProtocolName());
        deviceQueryWrapper.eq("device_name", device.getDeviceName());
        Integer selectCount = deviceMapper.selectCount(deviceQueryWrapper);
        if (selectCount > 0) {
            return ResultUtil.createSimpleFailureJson("该设备名称已存在");
        }


        log.info("插入设备：{}", device.toString());
        // 检查设备对象的数据格式是否符合要求
        String checkData = checkDeviceData(device);
        if (!checkData.equals("ok")) {
            return ResultUtil.createSimpleFailureJson(checkData);
        }
        deviceMapper.insert(device);

        return ResultUtil.createSimpleSuccessJson("设备添加成功");
    }


    /**
     * 检查设备对象的数据格式是否符合要求
     *
     * @param device
     * @return
     */
    public String checkDeviceData(Device device) {
        if (null == device.getDeviceName() || device.getDeviceName().trim().equals("")) {
            return "设备名称不能为空";
        } else {
            if (!device.getDeviceName().matches("^[a-z0-9A-Z]+$") && !device.getDeviceName().matches("[0-9]*") && !device.getDeviceName().matches("^[A-Za-z]+$")) {
                return "设备名称只能包含数字及字母";
            }
        }
        if (null == device.getHost() || device.getHost().trim().equals("")) {
            return "设备ip不能为空";
        } else {
            if (!this.validIp("*.*.*.*", device.getHost())) {
                return "设备ip格式有误";
            }
        }
        if (null == device.getPort()) {
            return "端口号不能为空";
        }

        if (null == device.getConnectionLimit() || device.getConnectionLimit().equals("")) {
            return "重连次数不能为空";
        } else {

            if (device.getConnectionLimit() > 100) {
                return "重连次数不可大于100";
            }
        }

        if (null == device.getTimeout() || device.getTimeout().equals("")) {
            return "超时时间不能为空";
        } else {

            if (device.getTimeout() > 30000) {
                return "超时时间不可大于30000";
            }
        }

        return "ok";
    }


    /**
     * @return
     * @Author sgw
     * @Date 2020/9/6 13:52
     * @Param
     * @Description validlIP 校验ip是否有效
     **/
    public Boolean validIp(String validIP, String ip) {
        if (!StringUtils.hasText(validIP)) {
            return true;
        }
        validIP = validIP.trim();
        if (!StringUtils.hasText(ip)) {
            return false;
        }
        ip = ip.trim();
        String ipReg = "^((1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])|\\*)\\."
                + "((1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)|\\*)\\."
                + "((1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)|\\*)\\."
                + "((1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)|\\*)$";
        /**校验ip的格式*/
        Pattern pattern = Pattern.compile(ipReg);
        Matcher ipMatcher = pattern.matcher(ip);
        if (!ipMatcher.matches()) {
            return false;
        }
        /**validIP 的格式*/
        Pattern oriPattern = Pattern.compile(ipReg);
        Matcher oriMatcher = oriPattern.matcher(validIP);
        if (!oriMatcher.matches()) {
            return false;
        }
        /**validIP 相同*/
        if (validIP.equals(ip)) {
            return true;
        }
        /**校验ip是否处在validlIP段内*/
        String[] oriIpArr = validIP.split("\\.");
        String[] ipArr = ip.split("\\.");
        Boolean hasStar = false;
        String star = "*";
        for (int i = 0; i < oriIpArr.length; i++) {
            String oriIp = oriIpArr[i];
            boolean flag = oriIp.equals(star);
            if (flag) {
                hasStar = flag;
            }
            if (hasStar && !flag) {
                return false;
            }
            if (!ipArr[i].equals(oriIp) && !oriIp.equals(star)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 分页查询设备
     * <p>
     * start应该是页数
     * limit应该是每页的个数
     * total是总数量
     *
     * @param start
     * @param limit
     * @param protocolName
     * @return String
     */
    public String queryDevice(Integer start, Integer limit, String protocolName) {
        log.info("查询设备，protocolName:{}，limit:{}，start:{}",protocolName,start,limit);

        QueryWrapper<Device> deviceQueryWrapper = new QueryWrapper<>();
        deviceQueryWrapper.eq("protocol_name", protocolName);
        Integer total = deviceMapper.selectCount(deviceQueryWrapper);

        Page<Device> devicePage = new Page<>();
        devicePage.setTotal(total);
        devicePage.setCurrent(start);
        devicePage.setSize(limit);

        IPage<Device> deviceIPage = deviceMapper.selectPage(devicePage, deviceQueryWrapper);
        List<Device> deviceList = deviceIPage.getRecords();

        ArrayList<BoschDevice> modbusDeviceList = new ArrayList<>();

        deviceList.forEach(device -> {
            modbusDeviceList.add(BoschDevice.reconvert(device));
        });

        GridDataResult<BoschDevice> deviceListResult = new GridDataResult<>();

        deviceListResult.setTotal(total);
        deviceListResult.setRoot(modbusDeviceList);

        return JSON.toJSONString(deviceListResult);
    }



    /**
     * 批量删除设备
     * <p>
     * 首先根据DeviceId删除变量表中对应设备的变量，然后根据DeviceId删除设备表中的设备
     *
     * @param deviceIdList
     * @return
     */
    public String deleteDevice(String[] deviceIdList) {
        if(deviceIdList.length>0){
            log.info("删除设备：",deviceIdList);
        }

        for (String deviceIdStr :deviceIdList) {
            int deviceId = Integer.parseInt(deviceIdStr);
            QueryWrapper<Point> pointQueryWrapper = new QueryWrapper<>();
            pointQueryWrapper.eq("device_id", deviceId);
            pointMapper.delete(pointQueryWrapper);

            deviceMapper.deleteById(deviceId);
        }
        return ResultUtil.createSimpleSuccessJson("设备信息删除成功");
    }


    /**
     * 根据id修改设备
     *
     * @param device
     * @return
     */
    public String updateDevice(Device device) {
        log.info("编辑设备：",device.toString());

        String checkData = this.checkDeviceData(device);
        if (!checkData.equals("ok")) {
            return ResultUtil.createSimpleFailureJson(checkData);
        }
        deviceMapper.updateById(device);
        return ResultUtil.createSimpleSuccessJson("设备修改成功");
    }



    /**
     * 获取设备表格格式
     */
    public String tableStructure() {



        // 1.deviceName属性
        Map<String, String> deviceNameMap1 = new HashMap<>();
        deviceNameMap1.put("message", "不允许为空");
        deviceNameMap1.put("required", "true");
        Map<String, String> deviceNameMap2 = new HashMap<>();
        deviceNameMap2.put("pattern", "^[a-z0-9A-Z]+$");
        deviceNameMap2.put("type", "string");
        deviceNameMap2.put("message", "只能为字母或字母+数字组合");
        List<Map> deviceNameValidate = new ArrayList<>();
        deviceNameValidate.add(deviceNameMap1);
        deviceNameValidate.add(deviceNameMap2);


        HashMap<String, Object> deviceName = new HashMap<>();
        deviceName.put("prop", "deviceName");
        deviceName.put("label", "设备名称");
        deviceName.put("type", "Input");
        deviceName.put("validate", deviceNameValidate);


        // 2.description属性
        Map<String, String> descriptionMap1 = new HashMap<>();
        descriptionMap1.put("message", "不允许为空");
        descriptionMap1.put("required", "true");
        List<Map> descriptionValidate = new ArrayList<>();
        descriptionValidate.add(descriptionMap1);


        HashMap<String, Object> description = new HashMap<>();
        description.put("prop", "description");
        description.put("label", "描述");
        description.put("type", "Input");
        description.put("validate", descriptionValidate);


        // 3.host属性
        Map<String, String> hostMap1 = new HashMap<>();
        hostMap1.put("message", "不允许为空");
        hostMap1.put("required", "true");
        Map<String, String> hostMap2 = new HashMap<>();
        hostMap2.put("pattern", "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
        hostMap2.put("type", "string");
        hostMap2.put("message", "必须为IP格式");
        List<Map> hostValidate = new ArrayList<>();
        hostValidate.add(hostMap1);
        hostValidate.add(hostMap2);


        HashMap<String, Object> host = new HashMap<>();
        host.put("prop", "host");
        host.put("label", "设备IP");
        host.put("type", "Input");
        host.put("validate", hostValidate);

        // 4.port属性
        Map<String, String> portMap1 = new HashMap<>();
        portMap1.put("message", "不允许为空");
        portMap1.put("required", "true");
        Map<String, String> portMap2 = new HashMap<>();
        portMap2.put("pattern", "^(([0-9])|([1-9]+[0-9]*))$");
        portMap2.put("type", "string");
        portMap2.put("message", "必须为整数");
        Map<String, String> portMap3 = new HashMap<>();
        portMap3.put("min", "0");
        portMap3.put("max", "string");
        portMap3.put("message", "必须为0-65535之间的整数");
        List<Map> portValidate = new ArrayList<>();
        portValidate.add(portMap1);
        portValidate.add(portMap2);
        portValidate.add(portMap3);


        HashMap<String, Object> port = new HashMap<>();
        port.put("prop", "port");
        port.put("label", "端口号");
        port.put("type", "Input");
        port.put("validate", portValidate);


        // 5.timeout属性
        Map<String, String> timeoutMap1 = new HashMap<>();
        timeoutMap1.put("message", "不允许为空");
        timeoutMap1.put("required", "true");
        Map<String, String> timeoutMap2 = new HashMap<>();
        timeoutMap2.put("pattern", "^(([0-9])|([1-9]+[0-9]*))$");
        timeoutMap2.put("type", "string");
        timeoutMap2.put("message", "必须为整数");
        Map<String, String> timeoutMap3 = new HashMap<>();
        timeoutMap3.put("min", "0");
        timeoutMap3.put("max", "30000");
        timeoutMap3.put("message", "必须为0-30000之间的整数");
        List<Map> timeoutValidate = new ArrayList<>();
        timeoutValidate.add(timeoutMap1);
        timeoutValidate.add(timeoutMap2);
        timeoutValidate.add(timeoutMap3);


        HashMap<String, Object> timeout = new HashMap<>();
        timeout.put("prop", "timeout");
        timeout.put("label", "超时时间");
        timeout.put("type", "Input");
        timeout.put("validate", timeoutValidate);


        // 6.connectionLimit属性
        Map<String, String> connectionLimitMap1 = new HashMap<>();
        connectionLimitMap1.put("message", "不允许为空");
        connectionLimitMap1.put("required", "true");
        Map<String, String> connectionLimitMap2 = new HashMap<>();
        connectionLimitMap2.put("pattern", "^(([0-9])|([1-9]+[0-9]*))$");
        connectionLimitMap2.put("type", "string");
        connectionLimitMap2.put("message", "必须为整数");
        List<Map> connectionLimitValidate = new ArrayList<>();
        connectionLimitValidate.add(connectionLimitMap1);
        connectionLimitValidate.add(connectionLimitMap2);


        HashMap<String, Object> connectionLimit = new HashMap<>();
        connectionLimit.put("prop", "connectionLimit");
        connectionLimit.put("label", "重连次数");
        connectionLimit.put("type", "Input");
        connectionLimit.put("validate", connectionLimitValidate);



        // 7.username属性
        Map<String, String> username1 = new HashMap<>();
        username1.put("message", "不允许为空");
        username1.put("required", "true");
        List<Map> usernameValidate = new ArrayList<>();
        usernameValidate.add(username1);


        HashMap<String, Object> username = new HashMap<>();
        username.put("prop", "username");
        username.put("label", "数据库用户名");
        username.put("type", "Input");
        username.put("validate", usernameValidate);




        // 8.password属性
        Map<String, String> password1 = new HashMap<>();
        password1.put("message", "不允许为空");
        password1.put("required", "true");
        List<Map> passwordValidate = new ArrayList<>();
        passwordValidate.add(password1);


        HashMap<String, Object> password = new HashMap<>();
        password.put("prop", "password");
        password.put("label", "数据库密码");
        password.put("type", "Input");
        password.put("validate", passwordValidate);

        // 9.dbName属性
        Map<String, String> dbName1 = new HashMap<>();
        password1.put("message", "不允许为空");
        password1.put("required", "true");
        List<Map> dbNameValidate = new ArrayList<>();
        dbNameValidate.add(dbName1);


        HashMap<String, Object> dbName = new HashMap<>();
        dbName.put("prop", "dbName");
        dbName.put("label", "数据库名");
        dbName.put("type", "Input");
        dbName.put("validate", dbNameValidate);

        // 8.filePath属性
        Map<String, String> filePath1 = new HashMap<>();
        password1.put("message", "不允许为空");
        password1.put("required", "true");
        List<Map> filePathValidate = new ArrayList<>();
        filePathValidate.add(filePath1);


        HashMap<String, Object> filePath = new HashMap<>();
        filePath.put("prop", "filePath");
        filePath.put("label", "文件路径");
        filePath.put("type", "Input");
        filePath.put("validate", filePathValidate);


        //equipmentForm：把上面的属性信息包装到一个map中
        List<Map> tableData = new ArrayList<>();
        tableData.add(deviceName);
        tableData.add(description);
        tableData.add(host);
        tableData.add(port);
        tableData.add(timeout);
        tableData.add(connectionLimit);
        tableData.add(username);
        tableData.add(password);
        tableData.add(dbName);
        tableData.add(filePath);


        Map<String, String> tableMap1 = new HashMap<>();
        tableMap1.put("width", "60");
        tableMap1.put("type", "selection");
        tableMap1.put("align", "center");
        Map<String, String> tableMap2 = new HashMap<>();
        tableMap2.put("title", "设备名称");
        tableMap2.put("align", "center");
        tableMap2.put("key", "deviceName");
        Map<String, String> tableMap3 = new HashMap<>();
        tableMap3.put("title", "描述");
        tableMap3.put("align", "center");
        tableMap3.put("key", "description");
        Map<String, String> tableMap4 = new HashMap<>();
        tableMap4.put("title", "设备IP");
        tableMap4.put("align", "center");
        tableMap4.put("key", "host");
        Map<String, String> tableMap5 = new HashMap<>();
        tableMap5.put("title", "端口号");
        tableMap5.put("align", "center");
        tableMap5.put("key", "port");
        Map<String, String> tableMap6 = new HashMap<>();
        tableMap6.put("title", "超时时间");
        tableMap6.put("align", "center");
        tableMap6.put("key", "timeout");
        Map<String, String> tableMap7 = new HashMap<>();
        tableMap7.put("title", "重连次数");
        tableMap7.put("align", "center");
        tableMap7.put("key", "connectionLimit");
        Map<String, String> tableMap8 = new HashMap<>();
        tableMap7.put("title", "数据库用户名");
        tableMap7.put("align", "center");
        tableMap7.put("key", "username");
        Map<String, String> tableMap9 = new HashMap<>();
        tableMap7.put("title", "数据库密码");
        tableMap7.put("align", "center");
        tableMap7.put("key", "password");
        Map<String, String> tableMap10 = new HashMap<>();
        tableMap7.put("title", "数据库名");
        tableMap7.put("align", "center");
        tableMap7.put("key", "dbName");
        Map<String, String> tableMap11 = new HashMap<>();
        tableMap7.put("title", "文件路径");
        tableMap7.put("align", "center");
        tableMap7.put("key", "filePath");
        List<Map> tableStyle = new ArrayList<>();
        tableStyle.add(tableMap1);
        tableStyle.add(tableMap2);
        tableStyle.add(tableMap3);
        tableStyle.add(tableMap4);
        tableStyle.add(tableMap5);
        tableStyle.add(tableMap6);
        tableStyle.add(tableMap7);
        tableStyle.add(tableMap8);
        tableStyle.add(tableMap9);
        tableStyle.add(tableMap10);
        tableStyle.add(tableMap11);


        Map<String, List> resMap = new HashMap<>();
        resMap.put("tableData", tableData);
        resMap.put("tableStyle", tableStyle);

        log.info("设备表单格式：{}", JSON.toJSONString(resMap));

        return JSON.toJSONString(resMap);
    }

    public static void main(String[] args) {
        DeviceService deviceService = new DeviceService();
        String tableStructure = deviceService.tableStructure();
        System.out.println(tableStructure);
    }

}
